package com.yctan.masterslave;

// 接受連線請求線程

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class Acceptor implements Runnable {
    /**
     * mainReactor监听的socket通道
     */
    private final ServerSocketChannel ssc;
    /**
     * 取得CPU核心數
     */
    private final int cores = Runtime.getRuntime().availableProcessors();
    /**
     * 创建核心數个selector給subReactor用
     */
    private final Selector[] selectors = new Selector[cores];
    /**
     * 当前可使用的subReactor索引
     */
    private int selIdx = 0;
    /**
     * subReactor线程
     */
    private TCPSubReactor[] r = new TCPSubReactor[cores];
    /**
     * subReactor线程
     */
    private Thread[] t = new Thread[cores];

    public Acceptor(ServerSocketChannel ssc) throws IOException {
        this.ssc = ssc;
        // 创建多個selector以及多個subReactor線程
        for (int i = 0; i < cores; i++) {
            // 创建多个selector
            selectors[i] = Selector.open();
            // 创建子处理器
            r[i] = new TCPSubReactor(selectors[i], ssc, i);
            // 创建线程
            t[i] = new Thread(r[i]);
            // 开始线程
            t[i].start();
        }
    }

    @Override
    public synchronized void run() {
        try {
            // 此方法相当于轮训，创建的selectors线程池来处理数据
            // 接受client连接请求
            SocketChannel sc = ssc.accept();
            System.out.println(Thread.currentThread().getName()+sc.socket().getRemoteSocketAddress().toString()
                    + " is connected.");
            if (sc != null) {
                // 设置为非阻塞
                sc.configureBlocking(false);
                // 暂停线程
                r[selIdx].setRestart(true);
                System.out.println("使一个阻塞住的selector操作立即返回");
                // 使一个阻塞住的selector操作立即返回
                selectors[selIdx].wakeup();
                // SocketChannel向selector[selIdx]注册一个OP_READ事件，然后返回该通道的key
                SelectionKey sk = sc.register(selectors[selIdx],
                        SelectionKey.OP_READ);
                System.out.println("使一个阻塞住的selector操作立即返回");
                // 使一个阻塞住的selector操作立即返回 
                selectors[selIdx].wakeup();
                // 重启线程
                r[selIdx].setRestart(false);
                // 給定key一个附加的TCPHandler對象
                sk.attach(new TCPHandler(sk, sc)); 
                if (++selIdx == selectors.length) {
                    selIdx = 0;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
